
module decode(clk, reset, stop, FeDe_instruccio, FeDe_pcActual, FeDe_pcPrediction, FeDe_pcMes, FeDe_taken, FeDe_excp,
	FeDe_NOP, DeAl_eALU, DeAl_eMUL, DeAl_eDIV, DeAl_eFLT, DeAl_eMEM, DeAl_eJMP, DeAl_eIO, DeAl_eWRB, DeAl_eMOV,
	DeAl_FRB, DeAl_wMEM, DeAl_wIO, DeAl_JMPType, DeAl_CMP, DeAl_OP, DeAl_intA, DeAl_intB, DeFe_enable, DeFe_pcexception,
	DeFe_jumpsys, DeFe_itlbwr, DeFe_itlbwridx, DeFe_itlbwren, DeAl_intC, DeAl_floatA, DeAl_floatB, DeAl_memSize, DeAl_pcActual, DeAl_pcPrediction, DeAl_eRETI, DeAl_eHALT,
	DeAl_pcMes, DeAl_taken, AlDe_Salt_incorrecte, DeAl_NOP,	DeAl_excp, DeAl_wTLB, DeAl_SRB, DeAl_eFLUSH, DeAl_eIID,
	EupDe_interrupcio,
	/*s'han d'implementar o mirar si es estan fets*/
	DeWb_valid, DeWb_pc, DeWb_robTail, DeWb_reg, DeWb_destiny, DeWb_latency, DeWb_exception,
	DeWb_regBypassA, DeWb_regTypeA, DeWb_regBypassB, DeWb_regTypeB, WbDe_exceptionWrite, WbDe_pc,
	WbDe_validBypassA, WbDe_valueBypassA, WbDe_validBypassB, WbDe_valueBypassB, WbDe_issue, WbDe_sizeRob,
	WbDe_STROB, WbDe_inout, WbBus_valid, WbBus_destinyWrite, WbBus_dataWrite, WbBus_addressWrite);

  input[15:0] FeDe_instruccio, FeDe_pcActual, FeDe_pcPrediction, FeDe_pcMes, FeDe_excp;
  input clk, reset, stop, FeDe_taken, AlDe_Salt_incorrecte, FeDe_NOP; 
  input EupDe_interrupcio;
  
  output[13:0] DeFe_itlbwr;
  output[2:0] DeFe_itlbwridx;
  output DeFe_itlbwren;
  
  output DeAl_eALU, DeAl_eMUL, DeAl_eDIV, DeAl_eFLT, DeAl_eMEM, DeAl_eJMP, DeAl_eIO, DeAl_eWRB, DeAl_eMOV,
  DeAl_FRB, DeAl_wMEM, DeAl_wIO, DeAl_JMPType, DeAl_CMP, DeAl_taken, DeAl_NOP, DeAl_eRETI, DeAl_eHALT,
  DeAl_wTLB, DeAl_SRB, DeAl_eFLUSH, DeAl_eIID;
  output[2:0] DeAl_memSize, DeAl_OP;
  output[31:0] DeAl_floatA, DeAl_floatB;
  output[15:0] DeAl_intA, DeAl_intB, DeAl_intC, DeAl_pcActual, DeAl_pcPrediction, DeAl_pcMes, DeAl_excp;
  
  output[15:0] DeWb_pc, DeWb_reg, DeWb_exception;			 
  output[3:0] DeWb_destiny, DeWb_latency;
  output[2:0] DeWb_robTail, DeWb_regBypassA, DeWb_regBypassB;
  output DeWb_valid, DeWb_regTypeA, DeWb_regTypeB;	
  output[15:0] DeFe_pcexception;
  output DeFe_enable, DeFe_jumpsys;
  
  input[31:0] WbDe_valueBypassA, WbDe_valueBypassB;
  input[15:0] WbDe_exceptionWrite, WbDe_pc;
  input[3:0] WbDe_issue;
  input[2:0] WbDe_sizeRob;
  input[1:0] WbDe_validBypassA, WbDe_validBypassB;
  input WbDe_STROB, WbDe_inout;	
  
  input[31:0] WbBus_dataWrite;	
  input[15:0] WbBus_addressWrite;
  input[3:0] WbBus_destinyWrite;
  input WbBus_valid;
  
  
  wire wire_esRb, wire_esSistema, wire_eMOV, wireJMPType, wire_eJMP, wire_eMUL, wire_eALU;
  wire wire_eDIV, wire_eFLT, wire_CMP, wire_eMEM, wire_wMEM, wire_eIO, wire_hihaRA, wire_hihaRB;
  wire wire_wIO, wire_FRB, wire_eWRB, wire_eRDS;
  wire wire_hihaBypassA, wire_hihaBypassB, wire_enableWBRE, wire_enableWBRF, wire_enableWBRS;
  wire wire_esCALLS, wire_esRETI, wire_esWRS;
  wire wire_acabaCALLS, wire_acabaEI, wire_acabaDI, wire_acabaRETI, wire_acabaGETIID;
  wire wire_acabaRDS, wire_acabaWRS, wire_acabaWRPI, wire_acabaWRVI, wire_acabaWRPD;
  wire wire_acabaWRVD, wire_acabaFLUSH, wire_acabaHALT, wire_Special;
  wire wire_jaCALLSiROBbuit, wire_jaRETIiROBbuit, wire_jaWRSiROBbuit, wire_jaINTERiROBbuit;
  wire wire_interrupcio, wire_RAoSA;
  /**senyals que avisen que ja pots fer les marranades que toqui per cada instr**/
  wire wire_enableFETCH, wire_NOP_a_ALU;
  wire[2:0] wire_MSize, wire_SImm, wire_idRB, wire_tail, wire_tail_mes1;
  wire[15:0] wire_offsetExtended, wire_intA, wire_intB, wire_MUX_Bypass_intB;
  wire[31:0] wire_floatA, wire_floatB;	  
  wire[1:0] wire_s_MUX_intB;
  wire[4:0] wire_codiSpecial;
  
  /* wires de systemAccess cap al SRB */
  wire wire_callSys, wire_retSys; 
  wire[15:0] wire_pcUp, wire_typeCallSys, wire_TLBAdress;
  
  /* wires de sortida del RB d sistema */
  wire[15:0] wire_systemA, wire_systemB;
  wire wire_sysInterr;				
  
  assign DeFe_itlbwr = WbBus_dataWrite[13:0];
  assign DeFe_itlbwridx	= WbBus_dataWrite[18:16];
  assign DeFe_itlbwren = WbBus_destinyWrite == 4'b1000	&& WbBus_addressWrite[15:13] == 3'b011;
  assign DeFe_enable = wire_enableFETCH;	   
  assign DeFe_jumpsys = wire_callSys || wire_retSys;
  
  assign DeAl_memSize = wire_MSize;
  assign DeAl_intC = wire_MUX_Bypass_intB;
  assign DeAl_pcActual = FeDe_pcActual;
  assign DeAl_eMOV = wire_eMOV;
  assign DeAl_eJMP = wire_eJMP;
  assign DeAl_JMPType = wireJMPType;
  assign DeAl_pcActual = FeDe_pcActual;
  assign DeAl_pcPrediction = FeDe_pcPrediction;
  assign DeAl_pcMes = FeDe_pcMes; 
  assign DeAl_taken	= FeDe_taken;
  assign DeAl_eALU = wire_eALU;
  assign DeAl_eMUL = wire_eMUL;
  assign DeAl_eDIV = wire_eDIV;
  assign DeAl_eFLT = wire_eFLT;
  assign DeAl_eMEM = wire_eMEM;
  assign DeAl_CMP = wire_CMP;	
  assign DeAl_eIO = wire_eIO;
  assign DeAl_wMEM = wire_wMEM;	
  assign DeAl_wIO = wire_wIO;
  assign DeAl_FRB = wire_FRB;
  assign DeAl_eWRB = wire_eWRB;
  assign DeAl_eRETI = wire_acabaRETI;
  assign DeAl_eHALT = wire_acabaHALT;
  assign DeAl_excp = {FeDe_excp[15:14], privilegiada, FeDe_excp[12:1], instrNoValida};
  assign DeWb_exception = {FeDe_excp[15:14], privilegiada, FeDe_excp[12:1], instrNoValida};
  assign DeWb_latency = {wire_eDIV,	wire_eFLT || wire_eMUL, wire_eMEM, 
  			wire_eALU || wire_eMOV || wire_eJMP || wire_esSistema || wire_eIO};
			  
  assign DeAl_NOP = wire_NOP_a_ALU || FeDe_NOP;
  assign DeWb_valid = ~(FeDe_NOP || wire_NOP_a_ALU || stop); 
  /** considero que les dades no son valides quan o ens entra una NOP desde FETCH
  o quan no emetem instr (o quan una instr no es valida??)**/
  
  assign DeWb_pc = FeDe_pcActual;
  assign DeWb_robTail = wire_tail; 
  assign DeWb_regTypeA = wire_eFLT && ~wire_eMEM;
  assign DeWb_regBypassA = FeDe_instruccio[8:6];
  assign DeWb_regTypeB = wire_eFLT;
  assign DeWb_regBypassB = wire_idRB;	 
  assign DeWb_reg = {wire_codiSpecial[3:0],9'b0_0000_0000,FeDe_instruccio[11:9]};
  
  assign wire_Special = WbBus_destinyWrite == 4'b1000;
  																								 																	   
  assign wire_acabaCALLS = wire_Special && WbBus_addressWrite[15:12] == 4'b1000;
  
  assign wire_acabaEI	= wire_Special && WbBus_addressWrite[15:12] == 4'b0000;
  assign wire_acabaDI = wire_Special &&	WbBus_addressWrite[15:12] == 4'b0001;
  assign wire_acabaRETI	= wire_Special && WbBus_addressWrite[15:12] == 4'b0100;
  assign wire_acabaGETIID = wire_Special &&	WbBus_addressWrite[15:12] == 4'b1011;
  assign wire_acabaRDS = wire_Special && WbBus_addressWrite[15:12] == 4'b0010;
  assign wire_acabaWRS = wire_Special && WbBus_addressWrite[15:12] == 4'b0011;
  assign wire_acabaWRPI = wire_Special && WbBus_addressWrite[15:12] == 4'b0110;
  assign wire_acabaWRVI	= wire_Special && WbBus_addressWrite[15:12] == 4'b0111;
  assign wire_acabaWRPD = wire_Special && WbBus_addressWrite[15:12] == 4'b1100;
  assign wire_acabaWRVD = wire_Special && WbBus_addressWrite[15:12] == 4'b1101;
  assign wire_acabaFLUSH =wire_Special && WbBus_addressWrite[15:12] == 4'b1000;
  assign wire_acabaHALT = wire_Special && WbBus_addressWrite[15:12] == 4'b1001;
  
  assign wire_enableWBRE = WbBus_destinyWrite == 4'b0000 || WbBus_destinyWrite == 4'b0100 || wire_acabaGETIID || wire_acabaRDS;
  assign wire_enableWBRF = WbBus_destinyWrite == 4'b0001 || WbBus_destinyWrite == 4'b0101;
  assign wire_enableWBRS = wire_acabaEI||wire_acabaDI||wire_jaRETIiROBbuit||wire_jaWRSiROBbuit;
  assign wire_hihaBypassA = WbDe_validBypassA == 2'b00;
  assign wire_hihaBypassB = WbDe_validBypassB == 2'b00;
  assign wire_s_MUX_intB = {wire_eMOV && FeDe_instruccio[8], wire_SImm[2:0] == 3'b000};
  
  assign wire_tail_mes1 = wire_tail + 1;
  
  /*********** detectar excepcions a DECODE **********/
  wire instrNoValida, privilegiada;
  wire wire_system;//akest cable surt del output 'system' del BRSistema OK!?
  
  assign privilegiada = (wire_esSistema || wire_eIO) && ~wire_system;
  assign instrNoValida = 
	wire_eMUL && (FeDe_instruccio[5] || FeDe_instruccio[4:3] == 2'b11) ||
	FeDe_instruccio[5] && (wire_eFLT || wire_eDIV) || 
	wire_eALU && wire_CMP && (FeDe_instruccio[5:3] == 3'b111 || FeDe_instruccio[4:3] == 2'b10) ||
	wire_eFLT && wire_CMP && (FeDe_instruccio[5] || FeDe_instruccio[4:3] == 2'b10) ||
	wireJMPType && (~FeDe_instruccio[5] || FeDe_instruccio[1:0] == 2'b10 || FeDe_instruccio[2:0] == 3'b101) ||
	wire_codiSpecial[4];
  
	/********************************/
	
	mux2 #(.WIDTH(16))
bypassSAoRA (.d0(wire_intA),
	.d1(wire_systemA),
	.s(wire_eRDS),
	.y(wire_RAoSA)
);
	
	/***************** logica Bypassos *****************/
	
	mux2 #(.WIDTH(16))
bypassRA (.d0(wire_RAoSA),
	.d1(WbDe_valueBypassA[15:0]),
	.s(wire_hihaRA && wire_hihaBypassA && ~wire_eRDS/**condicio seleccio**/),
	.y(DeAl_intA)
);

	mux2 #(.WIDTH(16))
bypassRB (.d0(wire_intB),
	.d1(WbDe_valueBypassB[15:0]),
	.s(wire_hihaRB && wire_hihaBypassB/**condicio seleccio**/),
	.y(wire_MUX_Bypass_intB)
);

	mux2 #(.WIDTH(32))
bypassFA (.d0(wire_floatA),
	.d1(WbDe_valueBypassA),
	.s(wire_hihaRA && wire_hihaBypassA && wire_eFLT/**condicio seleccio**/),
	.y(DeAl_floatA)
);

	mux2 #(.WIDTH(32))
bypassFB (.d0(wire_floatB),
	.d1(WbDe_valueBypassB),
	.s(wire_hihaRB && wire_hihaBypassB && wire_eFLT/**condicio seleccio**/),
	.y(DeAl_floatB)
);
	
	/***************************************************/
  decoder _decoder (
    .instruccio(FeDe_instruccio),
	.eALU(wire_eALU),
	.eMUL(wire_eMUL),
	.eDIV(wire_eDIV),
	.eFLT(wire_eFLT),
	.eJMP(wire_eJMP),
	.eMEM(wire_eMEM),
	.eIO(wire_eIO),
	.eWRB(wire_eWRB),
	.eMOV(wire_eMOV),
	.eRDS(wire_eRDS),
	.FRB(wire_FRB),
	.wMEM(wire_wMEM),
	.wIO(wire_wIO),
	.JMPType(wireJMPType),
	.CMP(wire_CMP),
	.memSize(wire_MSize),
	.sizeImm(wire_SImm),	/*quan no hi ha cap offset el valor es 000 q s'ha de fer?*/
	.esRb(wire_esRb),
	.esSistema(wire_esSistema),
	.hihaRA(wire_hihaRA),	   
	.hihaRB(wire_hihaRB),
	.wTLB(DeAl_wTLB),
	.SRB(DeAl_SRB),
	.eFLUSH(DeAl_eFLUSH),
	.eIID(DeAl_eIID),
	.esCALLS(wire_esCALLS),
	.esRETI(wire_esRETI),
	.esWRS(wire_esWRS)
	); 
	
	ROM_system_inst rom_system_inst (
	.address(FeDe_instruccio[4:0]),
	.data(wire_codiSpecial),
	.enable(wire_esSistema && FeDe_instruccio[5]),
	.esCALLS(wire_esCALLS)
);	 

cc_destiny cc_desti (.desti(DeWb_destiny),
	.eIO(wire_eIO),
	.wIO(wire_wIO),
	.FRB(wire_FRB),
	.eMEM(wire_eMEM),
	.wMEM(wire_wMEM),
	.esSistema(wire_esSistema),
	.esCALLS(wire_esCALLS),
	.eALU(wire_eALU),
	.eMOV(wire_eMOV),
	.eMUL(wire_eMUL),
	.CMP(wire_CMP),
	.eJMP(wire_eJMP),
	.memSize(wire_MSize)
);	

/* Extensor de signe i alineador del immediats */
	signex _signex(
	.inImm(FeDe_instruccio[7:0]),
	.sizeImm(wire_SImm),
	.alignImm(wire_MSize),
	.outImm(wire_offsetExtended)
	);

/* Banc de registres d'enters */	
  	rb16 BRInt (
	.clk(clk),
	.reset(reset),
	.writeD(WbBus_valid && wire_enableWBRE/**condicio escriptura**/),
	.regA(FeDe_instruccio[8:6]),
	.regB(wire_idRB),
	.regD(WbBus_addressWrite[2:0]),
	.valueA(wire_intA),
	.valueB(wire_intB),
	.valueD(WbBus_dataWrite[15:0])
);	

/* Banc de registres de coma flotant */
	rb32 BRfloat (
	.clk(clk),
	.reset(reset),
	.writeD(WbBus_valid && wire_enableWBRF/**condicio escriptura**/),
	.regA(FeDe_instruccio[8:6]),
	.regB(wire_idRB),
	.regD(WbBus_addressWrite[2:0]),
	.valueA(wire_floatA),
	.valueB(wire_floatB),
	.valueD(WbBus_dataWrite)
);

/* Banc de registres de sistema */
  srb16 BRSystem(
	.clk(clk), 
	.reset(reset), 
	.writeD(WbBus_valid && wire_enableWBRS/**condicio escriptura**/), 
	.regA(FeDe_instruccio[8:6]), 
	.regD(WbBus_addressWrite[2:0]), 
	.valueA(wire_systemA), /* connectat */
	.valueD(WbBus_dataWrite), 
	.callSys(wire_callSys), 
	.retSys(wire_retSys), 
	.pc(DeFe_pcexception), 
	.pcUp(wire_pcUp), 
	.typeCallSys(wire_typeCallSys), 
	.TLBAdress(wire_TLBAdress), 
	.interrupts(wire_sysInterr/* Estan activades les interrupcions */), 
	.system(wire_system/* Esta en mode sistema */)
  );

/* Logica de detecció d'acces o retorn de sistema */	  

  systemAccess  sAcces(
	.reset(reset), 
	.instPC(WbDe_pc), 
	.exceptions(WbDe_exceptionWrite), 
	.busValid(WbBus_valid), 
	.busDestinyWrite(WbBus_destinyWrite), 
	.busDataWrite(WbBus_dataWrite), 
	.busAdressWrite(WbBus_addressWrite), 
	.interruption(wire_jaINTERiROBbuit), 
	.jaCALLSiROBbuit(wire_jaCALLSiROBbuit), 
	.jaRETIiROBbuit(wire_jaRETIiROBbuit), 
	.callSys(wire_callSys), 
	.retSys(wire_retSys), 
	.pcUp(wire_pcUp), 
	.typeCallSys(wire_typeCallSys), 
	.TLBAdress(wire_TLBAdress), 
	.interrOK(wire_sysInterr), 
	.pc(FeDe_pcActual)
  );

	mux2 #(.WIDTH(3))
	muxEsRb (.d0(FeDe_instruccio[2:0]),
	.d1(FeDe_instruccio[11:9]),
	.s(wire_esRb),
	.y(wire_idRB)
);

	mux3 
	muxIntB (.d0(wire_offsetExtended),
	.d1(wire_MUX_Bypass_intB),
	.d2({wire_offsetExtended[7:0],wire_MUX_Bypass_intB[7:0]}),
	.s(wire_s_MUX_intB),
	.y(DeAl_intB)
);

	mux4 #(.WIDTH(3))
	muxCodiOP (.d0(FeDe_instruccio[5:3]),
	.d1(3'b100),
	.d2(FeDe_instruccio[2:0]),
	.d3({1'b0,1'b0,FeDe_instruccio[8]}),
	.s({wire_eJMP, wireJMPType}),
	.y(DeAl_OP)
);
	bloquejos 
	bloqs (
	.lat1(WbDe_issue[0]),
	.eALU(wire_eALU),
	.lat3(WbDe_issue[1]),
	.eMEM(wire_eMEM),
	.lat5(WbDe_issue[2]),
	.eMUL(wire_eMUL),
	.lat7(WbDe_issue[3]),
	.eDIV(wire_eDIV),
	.salt_incorrecte(AlDe_Salt_incorrecte),
	.sizeROB(WbDe_sizeRob),
	.validBypassA(WbDe_validBypassA),
	.validBypassB(WbDe_validBypassB),
	.hihaRA(wire_hihaRA),
	.hihaRB(wire_hihaRB),
	.esLD(wire_eMEM && ~wire_wMEM),
	.STon(WbDe_STROB),
	.esIO(wire_eIO),
	.WBinout(WbDe_inout),
	.esCALLS(wire_esCALLS),	/**falta**/
	.esRETI(wire_esRETI),	/**falta**/
	.esWRS(wire_esWRS),		/**falta**/
	.clk(clk),
	.reset(reset),
	.reset_FF_ALU(wire_NOP_a_ALU), /**fer output**/
	.we_FF_FETCH(wire_enableFETCH), /**fer output**/
	.acabaCALLS(wire_acabaCALLS), 
	.acabaRETI(wire_acabaRETI), 
	.acabaWRS(wire_acabaWRS), 
	.jaCALLSiROBbuit(wire_jaCALLSiROBbuit), 
	.jaRETIiROBbuit(wire_jaRETIiROBbuit), 
	.jaINTERiROBbuit(wire_jaINTERiROBbuit),
	.jaWRSiROBbuit(wire_jaWRSiROBbuit),
	.interrup(wire_interrupcio)
);

	ffd #(.n(3))
ff_tail (.D(wire_tail_mes1),
	.clk(clk),
	.reset(reset),
	.we(wire_enableFETCH && ~AlDe_Salt_incorrecte),
	.Q(wire_tail)
);

  endmodule
